/*******************************************************************************
 * Venice Noise Android Application
 * Copyright (C) 2011  Worcester Polytechnic Institute, Wesley Ripley
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; version 2
 * of the License
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 * 
 * If you plan to use or modify any of this code please contact Fabio Carrera (carrera.fabio@gmail.com)
 * Also please attribute any code used in the final product to the developers. 
 * 
 * Author: Wesley Ripley (wripley@wpi.edu) 
 *******************************************************************************/
package org.venicenoise.app.location;

import java.util.ArrayList;
import java.util.List;


import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;

/**
 * A general location service using a LocationPicker.
 * 
 * Implementation of the Template Pattern allowing easy creation
 * of LocationServices
 * 
 * @author Wesley Ripley
 * @version 12/15/2011
 *
 */
public class GeneralLocationService implements LocationService, LocationListener {

	private final LocationPicker locationPicker;
	private final LocationManager locationManager;
	
	protected Location bestLocation;
	private boolean isLocating = false;
	private List<LocationListener> listeners;
	

	/**
	 * Constructor for GeneralLocationService
	 * @param locationManager
	 * 		The location manager to request location updates from
	 * @param locationPicker
	 * 		The location picker defining how to choose one location over another
	 */
	public GeneralLocationService(LocationManager locationManager, LocationPicker locationPicker)
	{
		this.locationManager = locationManager;
		this.locationPicker = locationPicker;
	}
	
	public void startLocating() {
		if(isLocating())
		{
			return;
		}
		//ask for location updates from all providers
		for(String provider : locationManager.getProviders(false))
		{
			locationManager.requestLocationUpdates(provider, 0, 0, this);
		}
		isLocating = true;
	}

	public void stopLocating() {
		if(!isLocating())
		{
			return;
		}
		locationManager.removeUpdates(this);
		isLocating = false;
	}

	public boolean isLocating() {
		return isLocating;
	}

	public boolean locationAvailable() {
		return bestLocation != null;
	}

	public Location getLocation() {
		return new Location(bestLocation);
	}

	public void addLocationListener(LocationListener listener) {
		if(listeners == null)
		{
			listeners = new ArrayList<LocationListener>();
		}
		if(listener != null && !listeners.contains(listener))
		{
			listeners.add(listener);
		}
	}

	public void removeLocationListener(LocationListener listener) {
		if(listeners != null && listener != null && listeners.contains(listener))
		{
			listeners.remove(listener);
		}
	}
	
	public void notifyAllLocationChanged(Location location)
	{
		if(listeners == null)
		{
			return;
		}
		for(LocationListener listener : listeners)
		{
			listener.onLocationChanged(location);
		}
	}

	public void onLocationChanged(Location newLocation) {
		if(locationPicker.isBetterLocation(newLocation, bestLocation))
		{
			bestLocation = newLocation;
			notifyAllLocationChanged(bestLocation);
		}
	}

	public void onProviderDisabled(String provider) {
		// purposely blank, nothing needs to be done
	}

	public void onProviderEnabled(String provider) {
		locationManager.requestLocationUpdates(provider, 0, 0, this);
	}

	public void onStatusChanged(String provider, int status, Bundle extras) {
		// purposely blank, nothing needs to be done
	}

}
